#include <QDateTime>
#include <QtSql>
#include <QDebug>
#include <QInputDialog>
#include <QMessageBox>
#include <QDesktopServices>
#include "dialog.h"
#include "ui_dialog.h"
#include "macro.h"
#include "Tcp/aTcpServer.h"
#include "statusoperation.h"
#include "P2P/p2ppeer.h"
#include "P2P/threadpeer.h"
#include "P2P/p2pserver.h"
#include "ONSClient/onsmessenger.h"
#include "DBO/dbointhread.h"
#include "DBO/protocal.h"
#include "eventop.h"
#include "WebServer/webserverconfigdialog.h"
#include "ui_webserverconfigdialog.h"
#include "DBO/datamining.h"
#include "WebServer/webserver.h"
#include "WriteLog/threadWriteLog.h"
#include "Processes/threadprocess.h"
#include "Adapters/adapters.h"
#include "Adapters/AdapterTelnet/AdapterTelnet.h"
#include "ThreadSensorData/threadsensordata.h"
#include "SyncDataBase/dialogsyncdatabase.h"


/*
 处理应用程序到来的数据包
 */
void WeatherStation::processPendingDatagrams()
{
    QByteArray datagram;
    qint64 counter=0;
    isUdpOK=true;
    qDebug()<<"Data come";

    /***************读取UDP数据包****************************/
    do{
        if(counter>UDP_MAX_PendingCount)
        {
            QByteArray d;
            udpSocket->readDatagram(d.data(),0);

            return;
        }
        counter++;

        datagram.resize(udpSocket->pendingDatagramSize());

      udpSocket->readDatagram(datagram.data(),datagram.size(),&clientIP,&clientPort); //读数据包
      ui->sourceIPLabel->setText(clientIP.toString()); //显示源IP
      ui->sourcePortLabel->setText(QString::number(clientPort,10));  //显示源PORT
      if(ui->checkBoxWriteLog->isChecked())
        emit sigWriteLog(clientIP.toString().toUtf8()+":"+QByteArray::number(clientPort,10)+'\t'+
                       datagram.mid(0,200)); //写入数据包的前200字节

      if(ui->checkBoxShowText->isChecked())
      {
          //显示源SOCKET在对话框中
          ui->receivedPlainTextEdit->appendPlainText(clientIP.toString()+":"+QString::number(clientPort,10));
          //显示当前时间
          ui->receivedPlainTextEdit->appendPlainText(QDateTime::currentDateTime().toString("hh:mm:ss.zzz").toLatin1());

          ui->receivedPlainTextEdit->appendPlainText("> "+QString(datagram.data()));
        }
      if(!datagram.isEmpty())
         analyzeIncomeDatagram(datagram);

      //if(counter%20==19) //每连续处理20个包，处理下事件
        //qApp->processEvents(QEventLoop::AllEvents,MAX_ProcessEvents_MiliSecs);

    }while (udpSocket->hasPendingDatagrams());
    QByteArray d;
    udpSocket->readDatagram(d.data(),0);

}

/*
 处理网关到来的数据。到来的数据应当遵守网关接口协议。

 */
void    WeatherStation::processGWDatagrams()
{
    QByteArray datagram;
    QHostAddress  GWIP;
    quint16  GWPort;
    qint64 counter=0;

    isUdpGWOK=true;

    if(ui->checkBoxShowGW->isChecked())
        ui->receivedPlainTextEdit->appendPlainText("Packets come");

    /***************读取UDP数据包****************************/
    do{
        if(counter>UDP_MAX_PendingCount) //已经连续处理了太多的UDP包，抛弃其余的包，防止程序崩溃
        {
            QByteArray d;
            udpSocketForGW->readDatagram(d.data(),0);
            return;
        }
        counter++;

        datagram.resize(udpSocketForGW->pendingDatagramSize());
        udpSocketForGW->readDatagram(datagram.data(),datagram.size(),&GWIP,&GWPort); //读数据包

        if(ui->checkBoxWriteLog->isChecked())
        {
            if(datagram.startsWith("ERROR")||datagram.startsWith("INFO")||datagram.startsWith("WAR"))
                emit sigWriteLog(GWIP.toString().toLatin1()+":"+QByteArray::number(GWPort)+'\t'+datagram.mid(0,200));
            else
                emit sigWriteLog(GWIP.toString().toLatin1()+":"+QByteArray::number(GWPort)+'\t'+datagram.mid(0,100).toHex());
       }
        if(!datagram.isEmpty())
            analyzeGWDatagram(datagram,GWIP,GWPort,false);
      //  if(counter%20==19) //每连续处理20个包，处理下事件
         //   qApp->processEvents(QEventLoop::AllEvents,MAX_ProcessEvents_MiliSecs); //处理其他事务
    }while (udpSocketForGW->hasPendingDatagrams());
    QByteArray d;
    udpSocketForGW->readDatagram(d.data(),0);
}

/******************************************
  函数参数：QByteArray datagram
  功能：对datagram进行simplified。
  分析该datagram。
  ***************************************/
void WeatherStation::analyzeIncomeDatagram( QByteArray &datagram)
{
    QByteArray reply;

    if(clientIP.toString()==ONS_IP&&clientPort==ONS_Port) //来自ONS的数据包
     {
        ONSMessenger onsMesger(MY_URI,this);
        onsMesger.analyzeReceivedMsg(datagram);
        if(!onsMesger.GWIP.isEmpty()&&!onsMesger.GWPort.isEmpty())
        {
            myInternetIP=onsMesger.GWIP;
            if(onsMesger.URI.toUpper().contains("/MONITOR")&&(onsMesger.URI.toUpper().split("/MONITOR").at(0).toUpper().toUtf8()==
                    (tr(MY_URI)).toUpper().toUtf8()))
            {
                myInternetPort=onsMesger.GWPort;
            }
            else
            {
                myInternetPortVideo=onsMesger.GWPort;
            }
        }
        slotApdTxt(datagram);
        return;
      }

     QByteArray datagramSimplified=datagram.simplified();

     if(datagramSimplified.startsWith("ERR")||datagramSimplified.startsWith("WAR")||datagramSimplified.startsWith("INF"))
     {
         QByteArray str=DatagramOfHeartInternet;
         if(datagramSimplified.toUpper().startsWith(str.toUpper().simplified()))
             isInternetIPchanged=false; //收到了自己发送的包，说明ip没有发生变化
         slotApdTxt(datagram);
         return;
     }
     else if(datagramSimplified.mid(0.6).toUpper().startsWith("AGENT"))
     {
         //此处应当保证是没有经过任何处理的datagram
         emit sigPacketToAgent(datagram,clientIP.toString(),clientPort);
     }
     else if (datagramSimplified.mid(0,4).toUpper().startsWith("GET"))  //get请求
     {
         emit sigProcessClientData(datagram,clientIP.toString().toUtf8(),clientPort);
     }
     else if(datagramSimplified.mid(0,10).toUpper().startsWith("HELLO"))
     {
         udpSocket->writeDatagram("HI!",clientIP,clientPort);//UDP包发送至最近发包来的一个SOCKET
        return;
     }
     else if(datagramSimplified.mid(0,10).toUpper().startsWith("HI"))
     {
        return;
     }

    else if(datagramSimplified.mid(0,10).toUpper().startsWith("VIDEO")) //视频类命令
    {    
        if(datagramSimplified.toUpper().simplified()=="VIDEO ALIVE")
        {
            reply=p2PPeer->updateChildSocketTTLMap(clientIP.toString()+":"+QString::number(clientPort));
            udpSocket->writeDatagram(reply,clientIP,clientPort);//UDP包发送至最近发包来的一个SOCKET
        }
        else if(datagramSimplified.toUpper()=="VIDEO LIST SOURCES")
        {
            QByteArray sqlDataGram=
                    "select nam.NodeMacAddress,NodeName,SensorNameChinese from nodeaddressmap nam,"
                    "nodesensormap nsm,typemap tm where nam.nodeonwork=1 and nam.nodemacaddress=nsm.nodemacaddress "
                    "and nsm.sensoronwork=1 and nsm.sensorid=tm.sensorid and nsm.sensorid>=9 and nsm.sensorid<=24;";
           emit sigProcessClientData(sqlDataGram,clientIP.toString().toUtf8(),clientPort);
        }
        else
        {
            reply=myP2pServer->handleComingRequest(clientIP,clientPort,datagram);//由myp2PServer来做p2p方面的工作
            udpSocket->writeDatagram(reply,clientIP,clientPort);//UDP包发送至最近发包来的一个SOCKET
        }

    } //请求观看实时视频结束
    else if(datagramSimplified.mid(0,6).toUpper().startsWith("EVENT")) //事件类命令
    {
        eventOP->processEvent(datagramSimplified,clientIP.toString(),clientPort);
    }
    else if(datagramSimplified.endsWith(";"))  //以分号结尾，即是普通的SQL语句
    {
        emit sigProcessClientData(datagram,clientIP.toString().toUtf8(),clientPort);
     }
    else if(!datagramSimplified.mid(0,4).toUpper().startsWith("MAC")) //实时数据请求
    {
        emit sigProcessClientData(datagram,clientIP.toString().toUtf8(),clientPort);
    }//else if(!datagram.startsWith("Mac")) 结束

    else  //Mac开头的标准化命令，根据数据库表格中的记录进行解析
    {
        bool ok;
        QList <QByteArray> listParams=datagramSimplified.split(' ');
        if(listParams.size()>=2)
        {
            QString strTempMacAddr=listParams.at(1);
            qint64 tempMacAddr=strTempMacAddr.toLongLong(&ok);
            if(ok)
                emit sigConvProto(datagramSimplified,clientIP.toString(),clientPort,tempMacAddr);
        }
    }

}

void WeatherStation::slotSetIPAnalyzeIncomeDatagram( QByteArray datagram, QHostAddress parClientIP,quint16 parClientPort)
{
    clientIP=parClientIP;
    clientPort=parClientPort;
    analyzeIncomeDatagram(datagram);

}

void WeatherStation::on_pushButtonClear_clicked()
{
    ui->receivedPlainTextEdit->clear();
}

/*
 通知fromIP:fromPort,给toIP:toPort提供视频数据
 */
void  WeatherStation::shareWithPeer(QHostAddress fromIP, quint16 fromPort,
                   QHostAddress toIP, quint16 toPort, qint64 nodeMacAddr)
{
    p2PPeer->addOneChild(toIP.toString()+":"+QString::number(toPort),nodeMacAddr);
    qDebug()<<fromIP.toString()+":"+QString::number(fromPort)+"Asking for peer.";
}


/*
 发送UDP包给网关节点，说明连接已经断开了。
 在以下几种情况可能会调用该函数：
 1、TTL降到了0，连接断开。
 2、网关发送心跳包或者数据包给网关（这两者都会调用
StatusOperation::analyHeartPakcet(QByteArray &data)），
而连接实际上已经断开后没有建立。
 */
void    WeatherStation::notifyGWDisconnected(QHostAddress iP, quint16 port,qint64 nodeMacAddr)
{
    //qDebug()<<"aaaa";

    QByteArray destAddr;
    destAddr=destAddr.setNum(nodeMacAddr,16).rightJustified(16,'0',true);
    //qDebug()<<"baaa";

    QByteArray  dataGram=QByteArray::fromHex("aa4402"+destAddr+"888888888888888801001872010100ffff");
   // qDebug()<<"caaa";
    //qDebug()<<iP;
    if(!iP.toString().isEmpty()&&iP.toString().count(".")==3)
        udpSocketForGW->writeDatagram(dataGram,iP,port);
   // qDebug()<<"daaa";
}

void WeatherStation::slotRegMeToONS()
{
    QString objName=MY_URI;
    objName=objName.split("//").at(1);
    objName=objName.split(".").at(0);
    QByteArray msg,msgVideo;

    QUdpSocket udpSocketVideo;
    udpSocketVideo.bind(ServerPortData,QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);

    msg=onsMesger->genMesg(objName,"GW",OBJ_OWNER,OBJ_LOC,"Update",0,true);
    msgVideo=onsMesger->genMesg(objName+"V","GW",OBJ_OWNER,OBJ_LOC,"Update",0,true); //视频的URI在后面加上“V"
    for(int n=0;n<1;n++)
    {
        //注册
        udpSocket->writeDatagram(msg,QHostAddress(ONS_IP),ONS_Port);
        udpSocketVideo.writeDatagram(msgVideo,QHostAddress(ONS_IP),ONS_Port);
        slotApdTxt(msg);
        slotApdTxt(msgVideo);
/*
        if(udpSocketVideo.waitForReadyRead(UDP_MAX_WAIT_MSECS/100)) //等待回复。如果不等待，过早退出，可能导致临时变量udpSocketVideo发送失败
        {
            qDebug()<<"Record of GW updated.";
            break;
        }
  */

    }
    QTimer::singleShot(10000,this,SLOT(slotQueryONS())); //10s以后查询自己的IP等内容

}

void WeatherStation::slotQueryONS()
{
    QString objName=MY_URI;
    objName=objName.split("//").at(1);
    objName=objName.split(".").at(0);
    QByteArray msg,msgVideo;
    msg=onsMesger->genMesg(objName,"GW",OBJ_OWNER,OBJ_LOC,"Query",0,true);
    msgVideo=onsMesger->genMesg(objName+"V","GW",OBJ_OWNER,OBJ_LOC,"Query",0,true);

    for(int n=0;n<1;n++)
    {
        //查询
        udpSocket->writeDatagram(msg,QHostAddress(ONS_IP),ONS_Port);
        udpSocket->writeDatagram(msgVideo,QHostAddress(ONS_IP),ONS_Port);

        slotApdTxt(msg);
        slotApdTxt(msgVideo);

        /*
        if(udpSocket->waitForReadyRead(UDP_MAX_WAIT_MSECS)) //等待回复
        {
            break;
        }
        */
    }
}

void WeatherStation::slotApdTxt(QString text)
{
    if(ui->checkBoxShowText->isChecked())
         ui->receivedPlainTextEdit->appendPlainText("------"+QDateTime::currentDateTime().toString()+
                  "------\n"+text+"\n");
    if(ui->checkBoxWriteLog->isChecked())
        emit sigWriteLog(text.toUtf8());
}

WeatherStation::~WeatherStation()
{
    threadAgent->quit();  threadAgent->wait(500);
    threadClient->quit(); threadClient->wait(500);
    threadDBORelated->quit();threadDBORelated->wait(500);
   // threadOfProcess->quit();threadOfProcess->wait(500);
    threadOfWebServer->quit();threadOfWebServer->wait(500);
    threadWriteLog->quit();threadWriteLog->wait(500);
    threadSensorData->quit();threadSensorData->wait(500);

    if(ui->checkBoxWriteLog->isChecked())
        emit sigWriteLog("Server Stopped");
}

void WeatherStation::on_pushButtonExit_clicked()
{
    close();
}

void WeatherStation::closeEvent(QCloseEvent *)
{
    slotApdTxt(tr("请稍等，正在进行退出处理中..."));

    QString objName=MY_URI;
    objName=objName.split("//").at(1);
    objName=objName.split(".").at(0);


    //删除资源在ONS上的记录
    QList<qint64> listMac=statusOperation->addrTTLMap.keys();
    for(;listMac.size()>0;listMac.removeFirst())
    {
        QSqlQuery tempQuery(QSqlDatabase::database(DB_CON_NAME_WEATHERSTATION));

        if(tempQuery.exec("select NodeName from NodeAddressMap "
             " where NodeMacAddress="+QString::number(listMac.at(0),10)) )
        {
            if(tempQuery.next())
            {
                QByteArray nodeName=tempQuery.value(0).toByteArray();
                QByteArray msg=onsMesger->genMesg(nodeName,
                   "video",OBJ_OWNER,OBJ_LOC,"Delete",QString::number(listMac.at(0),10),true);
                for(int n=0;n<1;n++)
                {
                    udpSocket->writeDatagram(msg,QHostAddress(ONS_IP),ONS_Port);
                    slotApdTxt(msg);
                   // if(udpSocket->waitForReadyRead(UDP_MAX_WAIT_MSECS))
                    //    break;
                }
            }
        }
    }

    //删除平台自己在ONS的记录
    for(int n=0;n<UDP_MAX_SEND_TIMES;n++)
    {
        //先删除旧记录
        udpSocket->writeDatagram(onsMesger->genMesg(objName,"GW",OBJ_OWNER,OBJ_LOC,"Delete",0,true),
                                QHostAddress(ONS_IP),ONS_Port);
        if(udpSocket->waitForReadyRead(UDP_MAX_WAIT_MSECS))
        {
            slotApdTxt("....Record on ONS of GW deleted.");
            break;
        }

        QByteArray msgVideo=onsMesger->genMesg(objName+"V","GW",OBJ_OWNER,OBJ_LOC,"Delete",0,true); //视频的URI在后面加上“V"
        udpSocket->writeDatagram(msgVideo, QHostAddress(ONS_IP),ONS_Port);
        if(udpSocket->waitForReadyRead(UDP_MAX_WAIT_MSECS))
        {
            slotApdTxt("....Record on ONS Video of GW deleted.");
            break;
        }
    }
   // repaint();
    p2PPeer->quitThreadPeers();
   // threadDboRelatd->exit(0);
    //threadOfWebServer->exit(0);

    close();
}


void WeatherStation::slotProcessConvtedData(QByteArray gwData, QString appIP, quint16 appPort,qint64 nodeMacAddr,QByteArray baSNBase10)
{

    if(!regExpValidIP->exactMatch(appIP))
        return;

    QByteArray packet2Wsn=gwData;
    bool ok;
    if(packet2Wsn.startsWith("ERROR")||packet2Wsn.startsWith("INFO")||packet2Wsn.startsWith("WARN"))
    {
        slotApdTxt(packet2Wsn);
        udpSocket->writeDatagram(packet2Wsn+"\n",QHostAddress(appIP),appPort);
        return;
    }
     else
    {
        slotApdTxt("packet2WSN is: "+packet2Wsn.toHex());
    }

    bool isConnected=false;
    qint64 virtualMacAddr;
    QList <qint64> listMacs=statusOperation->addrSocketMap.keys();
    for(int n=0;n<listMacs.size()&&!isConnected;n++)
    {
        virtualMacAddr=listMacs.at(n);
        qint64 mask= Q_INT64_C(0x00ffffffffffffff);
        if((virtualMacAddr&mask)==(nodeMacAddr&mask))
        {
            isConnected=true;
            break;
        }
    }

    if(isConnected&&statusOperation->addrSocketMap.contains(virtualMacAddr))
    {
        QString strSocket=statusOperation->addrSocketMap.value(virtualMacAddr);
        QString strIP=strSocket.split(":").at(0);
        QString strPort=strSocket.split(":").at(1);
        qint64 len=-1;
        if(regExpValidIP->exactMatch(strIP))
            len=udpSocketForGW->writeDatagram(packet2Wsn,QHostAddress(strIP),strPort.toUInt(&ok,10));
        slotApdTxt("> packet2WSN ("+QByteArray::number(len)+" bytes) is sent to "+strIP+":"+strPort);
        QByteArray packetToApp="INFO: Packet is Sent to Node.\nNodeMac:"+QByteArray::number(nodeMacAddr)+
                "\nSN:"+baSNBase10+"\n";
        if(regExpValidIP->exactMatch(appIP))
            udpSocket->writeDatagram(packetToApp,QHostAddress(appIP),appPort);
    }
    else
    {
         ui->receivedPlainTextEdit->appendPlainText("Connection to this node not establish now.Cmd not sent to WSN ");
         if(regExpValidIP->exactMatch(appIP))
            udpSocket->writeDatagram("ERROR: Connection to this node not establish now..",QHostAddress(appIP),appPort);
    }


}

void WeatherStation::slotCmdAckToApp(QByteArray dataGram, QString appIP, quint16 appPort)
{
    slotApdTxt(QByteArray::number(udpSocket->writeDatagram(dataGram,QHostAddress(appIP),appPort))+
               tr("个字节的数据包发送给了App。")+"\n"+tr("数据包的内容为：")+"\n"+dataGram+
               tr("App的IP和端口为")+appIP+":"+QByteArray::number(appPort,10));
}

void WeatherStation::slotSendToNode(QByteArray data, qint64 paramMacAddr)
{
    QByteArray packet2Wsn=data;
    bool ok;
    if(packet2Wsn.startsWith("ERROR")||packet2Wsn.isEmpty())
    {
        return;
    }

    bool isConnected=false;
    qint64 virtualMacAddr(0);
    QList <qint64> listMacs=statusOperation->addrSocketMap.keys();
    for(int n=0;n<listMacs.size()&&!isConnected;n++)
    {
        virtualMacAddr=listMacs.at(n);
        qint64 mask= Q_INT64_C(0x00ffffffffffffff);
        if((virtualMacAddr&mask)==(paramMacAddr&mask))
        {
            isConnected=true;
            break;
        }
    }
    if(isConnected&&statusOperation->addrSocketMap.contains(virtualMacAddr))
    {
        QString strSocket=statusOperation->addrSocketMap.value(virtualMacAddr);
        QString strIP=strSocket.split(":").at(0);
        QString strPort=strSocket.split(":").at(1);
        if(regExpValidIP->exactMatch(strIP))
            udpSocketForGW->writeDatagram(packet2Wsn,QHostAddress(strIP),strPort.toUInt(&ok,10));
        slotApdTxt(packet2Wsn.toHex()+" is sent to "+strIP+":"+strPort);
    }
    else
    {        
         ui->receivedPlainTextEdit->appendPlainText("Connection to this GateWay not establish now.Cmd not sent to WSN ");
    }
}

void WeatherStation::slotShowErrorInfo(QString errorInfo)
{
    ui->receivedPlainTextEdit->appendPlainText("------"+
           QDateTime::currentDateTime().toString()+"-------\n"+errorInfo+"\n");
    if(ui->checkBoxWriteLog->isChecked())
        emit sigWriteLog(errorInfo.toUtf8());
}
void WeatherStation::slotShowErrorInfo(QByteArray errorInfo)
{
    ui->receivedPlainTextEdit->appendPlainText("------"+
           QDateTime::currentDateTime().toString()+"-------\n"+errorInfo+"\n");
    if(ui->checkBoxWriteLog->isChecked())
        emit sigWriteLog(errorInfo);
}

QByteArray WeatherStation::slotSendONSMesg(QString paraURI_ObjName, QString paraURI_ObjType, QString paraURI_ObjOwner, QString paraURI_ObjLocation, QString paraServiceType, QString paraID, bool paraIsGW, QString paraPWD)
{
    QByteArray msg=onsMesger->genMesg(
     paraURI_ObjName,paraURI_ObjType,paraURI_ObjOwner,paraURI_ObjLocation,paraServiceType,paraID,paraIsGW,paraPWD);
     udpSocket->writeDatagram(msg,QHostAddress(ONS_IP),ONS_Port);
     slotApdTxt(msg);
     return msg;
}


void WeatherStation::slotMsgBox(QString title, QString text)
{
    QMessageBox::information(this,title,text);
}

/*void WeatherStation::on_pushButtonAudio_clicked()
{
    //dialogMultiMedia->show();
}*/

void WeatherStation::analyzeGWDatagram(QByteArray datagram, QHostAddress GWIP, quint16 GWPort, bool isFromTcp)
{
    quint16 Pkt_Type,SN;
    qint64  sourceAddr;
    bool ok;

    QByteArray orignalDataGram=datagram;
    if(!threadDBORelated)
        return;

    statusOperation->sourceV4IP=GWIP.toString();
    statusOperation->sourcePort=GWPort;

    if(ui->checkBoxDebug->isChecked())
        slotApdTxt(isFromTcp?"From Tcp":"From UDP");

    ui->sourceIPLabel->setText(GWIP.toString());
    ui->sourcePortLabel->setText(QString::number(GWPort));
    if(ui->checkBoxDebug->isChecked()&&(!datagram.startsWith("ERR")&&!datagram.startsWith("INFO")&&!datagram.startsWith("WARN")))
        ui->receivedPlainTextEdit->appendPlainText("one packet from "+GWIP.toString()+" and it's:"+datagram.toHex().mid(0,100));
    else if(ui->checkBoxDebug->isChecked())
        ui->receivedPlainTextEdit->appendPlainText("one packet from "+GWIP.toString()+" and it's:"+datagram);

    if(threadDBORelated&&datagram.size()>=14&&(!datagram.startsWith("ERR")&&!datagram.startsWith("INFO")&&!datagram.startsWith("WARN")))
    {
        QByteArray head=datagram.mid(0,2).toHex();
        statusOperation->curHexProtocHead=head;

        if(!mapHeadProtocal.contains(head))
        {
            QMutex mutex;
            mutex.lock();
            if(!dboInThread->mapHeadProtocal.contains(head))
                dboInThread->readProtocolTable(head);
            if(!dboInThread->mapHeadProtocal.contains(head))
            {
                slotApdTxt("ERROR:No suitable protocol in WSN found whose head is "+head);
                mutex.unlock();
                return;
            }
            else
                mapHeadProtocal.insert(head,dboInThread->mapHeadProtocal.value(head));
            mutex.unlock();
        }

        Protocal curProtoc=mapHeadProtocal.value(head);
        if(datagram.size()<(curProtoc.pPkt_TypePos/8+curProtoc.pPkt_TypeSize/8)||
                datagram.size()<(curProtoc.pSourcePos/8+curProtoc.pSourceSize/8)||
                datagram.size()<(curProtoc.pSNPos/8+curProtoc.pSNSize/8)||
                datagram.size()<=(curProtoc.pSamplePos/8+2))
        {
            return;
        }

        Pkt_Type=datagram.mid(curProtoc.pPkt_TypePos/8,curProtoc.pPkt_TypeSize/8).toHex().toUShort(&ok,16);
        quint16 sizeDeclared=datagram.mid(curProtoc.pLenPos/8,curProtoc.pLenSize/8).toHex().toUInt(&ok,16);
        if(datagram.size()!=(sizeDeclared+4))
        {
            slotShowErrorInfo(tr("数据包的实际长度与数据包中的Len字段不符！数据包实际长度为：")
                              +QByteArray::number(datagram.size())+
                              tr(". 长度字段显示的长度为：")+QByteArray::number(sizeDeclared)+"+4");
            return;
        }
        sourceAddr=datagram.mid(curProtoc.pSourcePos/8,curProtoc.pSourceSize/8).toHex().toLongLong(&ok,16);
        QByteArray byteArraySrcAddr=datagram.mid(curProtoc.pSourcePos/8,curProtoc.pSourceSize/8);

        QByteArray  byteArraySN=datagram.mid(curProtoc.pSNPos/8,curProtoc.pSNSize/8); //暂存SN这个字节
        SN=datagram.mid(curProtoc.pSNPos/8,curProtoc.pSNSize/8).toHex().toUShort(&ok,16);


        /*
          当视频数据通过TCP发送给服务器时，要先通过UDP发送配置信息包。各类命令也会通过UDP来
          进行交互。
          */
        if(!statusOperation->addrSocketMap.contains(sourceAddr)&&isFromTcp)
        {
            return;
        }
        else if(statusOperation->addrSocketMap.contains(sourceAddr)&&isFromTcp)
        {
            //当数据包来自Tcp时，端口号是tcp的端口号，需要转换为UDP的端口号。因为命令下发都是用UDP的，
            //且一个mac地址与一个UDP的ip和端口唯一映射
            QString strSocket=statusOperation->addrSocketMap.value(sourceAddr);
            GWIP=strSocket.split(":").at(0);
            GWPort=strSocket.split(":").at(1).toUInt(&ok,10);
            statusOperation->sourceV4IP=GWIP.toString();
            statusOperation->sourcePort=GWPort;
        }

        if(ui->checkBoxDebug->isChecked())
            ui->receivedPlainTextEdit->appendPlainText("sourceAddr is "+QByteArray::number(sourceAddr));

        quint8 sensorID=datagram.mid(curProtoc.pSamplePos/8,1).toHex().toUShort(&ok,16);
        //该mac没有注册过,且是传感器数据包或视频数据包
        if(!statusOperation->addrTTLMap.contains(sourceAddr)&&(Pkt_Type==PktNormSensorType||Pkt_Type==PktVideoType))
        {
            //notifyGWDisconnected(GWIP,GWPort,sourceAddr);
            statusOperation->doWithMac(sourceAddr); //注册该mac
            statusOperation->doWithSensor(sourceAddr,sensorID);
            slotShowErrorInfo(tr("中间件启动后，第一次收到该节点该传感器的包:"+QByteArray::number(sourceAddr)+
                                 ":"+QByteArray::number(sensorID)));
        }
        //该mac没有注册过,且不是传感器数据包或视频数据包
        else if(!statusOperation->addrTTLMap.contains(sourceAddr)) //mac没有注册过
        {
            if(ui->checkBoxDebug->isChecked())
                slotShowErrorInfo(tr("中间件启动后，第一次收到该节点的包。")+QByteArray::number(sourceAddr));
             statusOperation->doWithMac(sourceAddr);
        }
        else //mac注册过
        {
            statusOperation->updateAddrTTLMap(sourceAddr,TTL_MAX);  //当做心跳处理
            //由于UDP端口号可能变化，所以要及时更新
            statusOperation->addrSocketMap.insert(sourceAddr,GWIP.toString()+":"+QString::number(GWPort));
        }

        if(ui->checkBoxDebug->isChecked())
            ui->receivedPlainTextEdit->appendPlainText("macAddr is "+
               QString::number(sourceAddr)+" GWIP is"+GWIP.toString()+"  GWPort is"
               +QString::number(GWPort)+" SN is"+QString::number(SN,10));

        if(Pkt_Type==PktNormSensorType||Pkt_Type==PktEventSensorType) //普通传感器数据或事件型传感数据包,转发给databasecom
        {
            QByteArray baAddrSensor=QByteArray::number(sourceAddr,10)+":"+QByteArray::number(sensorID,10);
            if(!statusOperation->addrSensorTTLMap.contains(baAddrSensor))
            {
                if(ui->checkBoxDebug->isChecked())
                    slotShowErrorInfo(tr("中间件启动后，第一次收到该节点该传感器的包:"+QByteArray::number(sourceAddr)+
                                         ":"+QByteArray::number(sensorID)));
                statusOperation->doWithSensor(sourceAddr,sensorID);
            }
            else
            {
                statusOperation->updateAddrSensorTTLMap(baAddrSensor,TTL_MAX); //传感器的心跳
            }

            emit sigProcessSensorData(datagram,GWIP,GWPort);
            return;
        }
         datagram.remove(0,curProtoc.pSamplePos/8);
         datagram.chop(2);

        if(Pkt_Type==PktVideoType) //视频包
        {
            QByteArray baAddrSensor=QByteArray::number(sourceAddr,10)+":"+QByteArray::number(sensorID,10);
            if(!statusOperation->addrSensorTTLMap.contains(baAddrSensor))
            {
                statusOperation->doWithSensor(sourceAddr,sensorID);
            }
            else
            {
                statusOperation->updateAddrSensorTTLMap(baAddrSensor,TTL_MAX); //传感器的心跳
            }

            if(ui->checkBoxDebug->isChecked())
                ui->receivedPlainTextEdit->appendPlainText("before distriVideo");

            datagram.prepend(byteArraySN);
            datagram.prepend(byteArraySrcAddr);

            p2PPeer->distriVideo(datagram,sourceAddr); //分发数据
            datagram.remove(0,byteArraySN.size()+byteArraySrcAddr.size()); //把前面额外添加的SN去掉
            if(ui->checkBoxDebug->isChecked())
                ui->receivedPlainTextEdit->appendPlainText("after distriVideo.\ndatagram "
                       " size is"+QString::number(datagram.size())+"\nGoint to enter "
                       "storeVideo(datagram,macAddr,SN)");
            emit sigStoreVideo(datagram,sourceAddr,SN,&(statusOperation->tableNameList),
                               &(statusOperation->tableNamePrefix),&(statusOperation->newMacList));
            if(ui->checkBoxDebug->isChecked())
                ui->receivedPlainTextEdit->appendPlainText("after storeVideo()");
        }
        else if(Pkt_Type==PktNodeInfo)  //配置信息包
            statusOperation->analyNodeInfoPacket(datagram,sourceAddr);
        else if(Pkt_Type==PktQurySensorInfo)  //信息查询包
            statusOperation->analyQuerySensorInfo(datagram,sourceAddr);
        else if(Pkt_Type==PktHeartBeat)  //心跳包
        {
            slotApdTxt("Heart Packet from "+QByteArray::number(sourceAddr));
            if(!statusOperation->analyHeartPakcet(datagram,sourceAddr)) //如果连接已经断开
             {
                //notifyGWDisconnected(GWIP,GWPort,sourceAddr);
            }
        }
        else if((Pkt_Type&0xf0)==PktCmdAckPrimaryType) //命令回复包
        {
             emit sigCmdAck(orignalDataGram);
        }
    }
}

void WeatherStation::slotTimerEventForInternetHeart()
{
   // udpSocket->writeDatagram("INFO:Hello",QHostAddress(heartInternetIP),heartInternetPort);
    //<一种NAT端口映射保持的自适应算法>一文中说，可以把数据发给自己的因特网IP和端口，来保持映射关系

    quint16 port;
    bool ok;
    if(!isUdpOK)
    {
        slotShowErrorInfo(QStringLiteral("Error occured to udpSocket!"));
        udpSocket->close();
        udpSocket->bind(aServerPort);
        QByteArray d;
        udpSocket->readDatagram(d.data(),0);
    }
    if(!isUdpGWOK)
    {
        slotShowErrorInfo(QStringLiteral("Error occured to udpSocketGW!"));
        udpSocketForGW->close();
        udpSocketForGW->bind(serverPortForGW);
        QByteArray d;
        udpSocketForGW->readDatagram(d.data(),0);
    }
    isUdpOK=false;
    isUdpGWOK=false;

    if(isInternetIPchanged||myInternetIP.isEmpty()||myInternetPort.isEmpty()||myInternetPortVideo.isEmpty())
    {
        slotRegMeToONS();
    }
    isInternetIPchanged=true; //在服务器收到自己发送的DatagramOfHeartInternet后，将该变量置为false

    if(regExpValidIP->exactMatch(myInternetIP))
    {
        if(!myInternetPort.isEmpty())
        {
            port=myInternetPort.toUShort(&ok);
            if(ok)
               udpSocket->writeDatagram(DatagramOfHeartInternet,QHostAddress(myInternetIP),port);
            else
                udpSocket->writeDatagram("INFO:Just Test Socket.",QHostAddress(aServerIP),aServerPort);
        }
        else
            udpSocket->writeDatagram("INFO:Just Test Socket.",QHostAddress(aServerIP),aServerPort);

        if(!myInternetPortVideo.isEmpty())
        {
            port=myInternetPortVideo.toUShort(&ok);
            if(ok)
            {
                QUdpSocket udpSocketVideo;
                udpSocketVideo.bind(ServerPortData,QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);
                udpSocketVideo.writeDatagram(DatagramOfHeartInternet,QHostAddress(myInternetIP),port);
            }
        }
    }
    else
        udpSocket->writeDatagram("INFO:Just Test Socket.",QHostAddress(aServerIP),aServerPort);

    udpSocketForGW->writeDatagram("INFO:Just Test Socket GW.",QHostAddress(aServerIP),serverPortForGW);

}

void WeatherStation::slotClientDataProcessDone(QByteArray result, QByteArray IP, quint16 port)
{
    if(!regExpValidIP->exactMatch(IP))
        return;

    if(ui->checkBoxWriteLog->isChecked())
        emit sigWriteLog(result.mid(0,500)+" is written to "+IP+":"+QByteArray::number(port));
    udpSocket->writeDatagram(result,(QHostAddress)((QString)IP),port);
}

/*
void WeatherStation::on_pushButtonHomePage_clicked()
{
    QDesktopServices::openUrl(QUrl("www.wsn.org.cn"));
}
*/



void WeatherStation::on_pBSync_clicked()
{
    dialogSyncDB->exec();
}

void WeatherStation::slotSendPacket2App(QByteArray packet, QString appIP, quint16 appPort)
{
    udpSocket->writeDatagram(packet,QHostAddress(appIP),appPort);
}
